package jsu.weizixuan.likesystem.job;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.retry.support.RetryTemplate;
import org.springframework.stereotype.Component;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;

@Component
@Slf4j
@RequiredArgsConstructor
public class RetryableEventSender {

    private final RabbitTemplate rabbitTemplate;
    private final RetryTemplate retryTemplate;
    @Qualifier("senderThreadPool")
    private final ExecutorService executor;

    /**
     * 业务线程直接调用，立即返回 CompletableFuture
     */
    public CompletableFuture<Void> sendAsync(String exchange, String routingKey, Object payload) {
        return CompletableFuture.runAsync(() -> doSendWithRetry(exchange, routingKey, payload), executor);
    }

    private void doSendWithRetry(String exchange, String routingKey, Object payload) {
        retryTemplate.execute(context -> {
            try {
                rabbitTemplate.convertAndSend(exchange, routingKey, payload, m -> {
                    m.getMessageProperties().setContentType("application/json");
                    return m;
                });
                log.debug("消息发送成功，第 {} 次", context.getRetryCount() + 1);
//                throw new AmqpException("消息发送失败");
                // 成功则结束重试
                return null;
            } catch (AmqpException e) {
                log.warn("消息发送失败，第 {} 次，继续重试", context.getRetryCount() + 1, e);
                throw e;                     // 抛异常才会触发重试
            }
        }, recovery -> {                     // 重试耗尽后执行
            handleFinallyFail(payload);
            return null;
        });
    }

    private void handleFinallyFail(Object payload) {
        // TODO: 落库、写 Redis、发告警、后续定时补偿
        log.error("消息经过 {} 次重试后仍失败，记录到失败表 => {}", 3, payload);

    }
}